﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using RouterControl.IO;
using Microsoft.HomeServer.SDK.Interop.v1;
using System.Runtime.InteropServices;

namespace RouterControl.Service
{
	public sealed class UpdateChecker
	{
		private static readonly UpdateChecker _instance = new UpdateChecker();

		public static UpdateChecker Instance
		{
			get { return _instance; }
		}

		private readonly log4net.ILog _log = log4net.LogManager.GetLogger(typeof(UpdateChecker));
		private Timer _timer;
		private object _checkLock = new object();
        private Whs.WhsNotification _notification;

		public DateTime LastCheck
		{
			get;
			private set;
		}

        public Web.ReleaseInfo? NewVersion
		{
			get;
            private set;
		}

		private void OnTick(object state)
		{
			try
			{
				DoCheck();
			}
			catch (Exception x)
			{
				_log.Warn("Failed to check for update", x);
			}
		}

		public void DoCheckManually()
		{
			_log.Info("Checking for update manually...");

			try
			{
				DoCheck();
			}
			catch (Exception x)
			{
				_log.Error("Failed to check for update manually", x);

				throw;
			}
		}

		private void DoCheck()
		{
			lock (_checkLock)
			{
				try
				{
					if (_log.IsDebugEnabled)
						_log.DebugFormat(
							"Checking for update for {0} (#{1})...",
							RouterControlVersion.VersionString,
							RouterControlVersion.VersionId
							);

                    using (var wsc = new Web.RouterControlWS2Factory())
					{
						var nv = wsc.Channel.GetNewerVersion3(
                            Whs.RouterControlRegistry.GetInstanceId().ToString(),
                            RouterControlVersion.VersionId,
                            RouterControlVersion.VersionIsBeta
                            );

                        if (Properties.Settings.Default.DEV_ForceUpdateMode ||
                            (nv.ReleaseId > RouterControlVersion.VersionId))
                        {
                            this.NewVersion = nv;
                        }
                        else
                        {
                            this.NewVersion = null;
                        }
					}
	
					// store this check
					this.LastCheck = DateTime.Now;
	
					Properties.States.Default.CheckUpdateLastCheck = this.LastCheck;
	
					Properties.States.Default.Save();
	
					// finalize
					if (this.NewVersion == null)
					{
						_log.Info("No new update found");

                        _notification.HideNotification();
					}
					else
					{
						_log.Info("Update found: " + this.NewVersion.Value.VersionStr);

                        _notification.Title = string.Format(
						    Properties.Resources.txtUpdateAvailableNotificationTitle,
                            this.NewVersion.Value.VersionStr
						    );

                        _notification.Description = string.Format(
                            Properties.Resources.txtUpdateAvailableNotificationDesc,
                            this.NewVersion.Value.VersionStr
                            );

                        _notification.ShowNotifcation();
					}
				}
				catch (Exception e)
				{
					_log.Error("Failed to check for update", e);

					throw;
				}
			}
		}

		private UpdateChecker()
		{
			if (_log.IsDebugEnabled)
				_log.Debug("Creating singleton");

			try
			{
				// notification
                _notification = new Whs.WhsNotification(Whs.Properties.Constants.UpdateNotificationId)
                {
                    Severity = WHS_Notification_Severity.WHS_WARNING
                };

				// load state
				try
				{
					this.LastCheck = Properties.States.Default.CheckUpdateLastCheck;
				}
				catch
				{
					_log.Warn("Failed to read CheckUpdateLastCheck state");
	
					this.LastCheck = DateTime.MinValue;
				}
	
				// initialize update check timer
				_timer = new Timer(
					new TimerCallback(OnTick),
					null,
					1000,
					(1000 * 60 * Properties.Settings.Default.CheckUpdateIntervalMinutes)
					);
			}
			catch (Exception e)
			{
				_log.Fatal("Failed to create singleton", e);

				throw;
			}

		}
	}
}
